package com.naiterui.ehp.bs.weixin.security.util;

import com.naiterui.ehp.bs.weixin.security.bean.JwtUser;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class JwtTokenUtil {

    public static final String USER_TYPE_KEY = "userType";
    public static final String USER_ID_KEY = "userId";

    /**
     * 通过源数据生成令牌
     */
    public static String generateToken(Map<String, Object> claims, String secret, Long expiration) {
        Date expirationDate = new Date(System.currentTimeMillis() + expiration * 1000);
        return Jwts.builder().setClaims(claims).setExpiration(expirationDate).signWith(SignatureAlgorithm.HS512, secret).compact();
    }

    /**
     * 从令牌中获取源数据
     */
    public static Claims getClaimsFromToken(String token, String secret) {
        Claims claims;
        try {
            claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
        } catch (Exception e) {
            claims = null;
        }
        return claims;
    }

    /**
     * 生成令牌
     */
    public static String generateToken(JwtUser jwtUser, String secret, Long expiration) {
        Map<String, Object> claims = new HashMap<>(2);
        claims.put(Claims.SUBJECT, jwtUser.getUsername());
        claims.put(Claims.ISSUED_AT, new Date());
        claims.put(USER_TYPE_KEY, jwtUser.getUserType());
        claims.put(USER_ID_KEY, jwtUser.getUserId());
        return generateToken(claims, secret, expiration);
    }

    /**
     * 从令牌中获取用户Id
     */
    public static Long getUserIdFromToken(String token, String secret) {
        Long userId;
        try {
            Claims claims = getClaimsFromToken(token, secret);
            userId = claims.get(USER_ID_KEY, Long.class);
        } catch (Exception e) {
            userId = null;
        }
        return userId;
    }

    /**
     * 从令牌中获取用户名
     */
    public static String getUserNameFromToken(String token, String secret) {
        String userName;
        try {
            Claims claims = getClaimsFromToken(token, secret);
            userName = claims.getSubject();
        } catch (Exception e) {
            userName = null;
        }
        return userName;
    }

    /**
     * 判断令牌是否过期
     */
    public static Boolean isTokenExpired(String token, String secret) {
        try {
            Claims claims = getClaimsFromToken(token, secret);
            Date expiration = claims.getExpiration();
            return expiration.before(new Date());
        } catch (Exception e) {
            return true;
        }
    }

    /**
     * 刷新令牌
     */
    public static String refreshToken(String token, String secret, Long expiration) {
        String refreshedToken;
        try {
            Claims claims = getClaimsFromToken(token, secret);
            claims.put(Claims.ISSUED_AT, new Date());
            refreshedToken = generateToken(claims, secret, expiration);
        } catch (Exception e) {
            refreshedToken = null;
        }
        return refreshedToken;
    }

    /**
     * 验证令牌
     */
    public static Boolean validateToken(String token, String secret, JwtUser jwtUser) {
        Long userId = getUserIdFromToken(token, secret);
        return userId != null && (userId.equals(jwtUser.getUserId()) && !isTokenExpired(token, secret));
    }

    /**
     * token装载JwtUser
     */
    public static JwtUser populateUser(String token, String secret) {
        JwtUser jwtUser;
        try {
            Claims claims = getClaimsFromToken(token, secret);
            Long userId = claims.get(USER_ID_KEY, Long.class);
            Integer userType = claims.get(USER_TYPE_KEY, Integer.class);
            jwtUser = new JwtUser(userType, userId, new Date());
            jwtUser.setToken(token);
        } catch (Exception e) {
            log.error("JwtUser populateUser ERROR , token inviled");
            jwtUser = null;
        }
        return jwtUser;
    }

    public static void main(String[] args) {
        String token = "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxMzUiLCJ1c2VyVHlwZSI6MCwiZXhwIjoxNjIyMTg0MTM2LCJpYXQiOjE2MjE1NzkzMzY2OTgsInVzZXJJZCI6MTM1fQ.YXOkHxGP8MV7HfOUx_y9yoaiXHrYpI7tvNbkPLdI4veJg5zxALMsVPKKM75UdIYKF38x32Xi6HR9PYvsLuMeVw";
        System.out.println(getUserIdFromToken(token, "defaultSecret"));
    }
}
